Fpii
fpii ist eine funktionale und objektorientierte Programmiersprache, die auf den von John Backus vorgeschlagenen FP-Systemen aufbaut. Die Objektorientierung ist auf die Polymorphie der Methoden in einem Klassenobjekt samt Vererbung reduziert. fpii unterstützt als variablenfreie Programmiersprache keine globalen Variablen und auch keine lokalen Variablen, was aber durch die Verwendung von dict(ionary)-Objekten kompensiert wird. Die Kombinatoren und anderen Operatoren werden in der Infix-Schreibweise in den Tupeln verwendet. Das Infix-Schema wurde auch auf die Objekte übertragen, um nur ein Klammernpaar, das der Listendarstellung, generatorentauglich einzusetzen. Die Quelltexte werden mittels eines JIT-Compilers in eine interne (verkettete) Listendarstellung umgewandelt, wie das bei der Programmiersprache LISP der Fall ist. Diese interne Darstellung wird dann von einem Interpreter verarbeitet. Seiteneffekte werden statt der Ausgabe der Resultate durch fios-Objekte ausgelöst. In der Regel ist die Verarbeitungsrichtung rechts-vor-links wie bei APL. Eine Ausnahme ist zum Beispiel die if-else-Struktur: p1 -> f1;p2 -> f2;etc Datentypen * (1 + 2) ist ein Beispiel für die Gruppe der Funktions-Terme. * (klasse1 of element1 element2 element3 ...) ist ein Objekt, erkennbar an dem of. * 12 ist ein Beispiel für float, atomarer Datentyp. * name1 ist ein ident, atomarer Datentyp. * 'A' ist ein Beispiel für char, ein atomarer Datentyp. * ( ) ist der null-Datentyp. Anwendungsbeispiele 1:(list of aa bb cc) --> aa 2:(list of aa bb cc) --> bb pop:(list of aa bb cc) --> (list of bb cc) reverse:(string of 'hallo') --> (string of 'ollah') ((1='0')->*pop):(string of '007') --> (string of '7') "löscht die führenden Nullen mit einer while-Schleife (->*)" ucase a string of 'hallo' --> (string of 'HALLO') "a ist der Mapping-Operator, der ucase auf die string-Elemente anwendet" (inc°2):(list of 33 44 55) --> 45 "(°) verkettet die Funktion 2 mit dem darauffolgendem Increment" (4,2,1,3,nil):(list of ein ist satz dies) --> (list of dies ist ein satz) Quicksort qsort:=(nilp->id; ((qsort°3)+1,qsort°4) °((not°nilp°2)->*1,(pop°2),(1>1°2)->(((1°2),3),4,nil);3,((1°2),4),nil) °1,pop,cof,cof,nil) Length mit Instanzenvariablen (im dict-Objekt) vlength:=((y#)°((not°nilp°x#)->*(y#=inc°y#)°(x#=pop°x#))°(y#=0&)°(id<-x)°id,nil) Beispiel für den Gebrauch von fios-Objekten timeloop:=((op;=time&),(iof;=((self;=console of),(op;=output&),(arg;=result),(iof;=timeloop&),io)&),io) "wenn in der Ausführumgebung timeloop getippt wird, so wird die Uhrzeit in einer Endlosschleife angezeigt." Objektorientierung Definitionsschema für Klassenbezeichner: klasse1:=(class of superklasse1 selektor1 methode1 selektor2 methode2 ... ... ) Definitionschema für Operatoren, Definition der Methoden und Funktionen: operator1:=(selektor1 eeop funktion_für_atomare_datentypen1) methode1:=(((1°self)*(1°arg))+((2°self)*(2°arg))) argument1:=(list of 3 2) objektorientierte Anwendung: (klasse1 of 12 15) operator1 argument1 --> 66 "Was passiert hier?" variablenfrei versus lambda Variablen haben den Vorteil, dass dem zugeordneten Wert ein kurze Beschreibung gegeben werden kann. Möchte man Variablen verwenden, wie beim lambda-Kalkül, muss man sich allerdings für eine Bindungsstrategie entscheiden, der lexikalischen Bindung oder der dynamischen Bindung mit samt ihren Nachteilen. Variablenfrei Programmieren bedeutet stattdessen Zahlen für die Positionen der Parameter zu gebrauchen, dardurch fällt das mitzuführende Environment (Liste der lambda-Bindungen) weg. Wo liegen die Nachteile der jeweiligen Bindungsstrategien? dynamic scope und static scope ? Der Gebrauch von Variablen ist sehr bequem und einfach, die Bindungsstrategien weisen jedoch einige Schwachstellen auf. Die folgenden Argumentationen werden mit LISP dokumentiert, da es den lambda-Kalkül unterstützt. Schwachstelle der dynamischen Bindung ; es wird ein LISP mit dynamischer Bindung verwendet (set 'pi 3.141592) (defun kreisflaeche ® (* pi (* r r))) ; noch läuft alles ok (kreisflaeche 10) --> 314.1592 ; es wird eine Erweiterung durchgeführt (defun kreisflaechemitdurchmesser (pi d) (kreisflaeche (/ d 2))) ; nun passiert etwas unerwartetes (kreisflaechemitdurchmesser 3.15 20) --> 315 ; es kommt ein falsches Ergebnis zustande, was auf die dynamische Bindung zurückzuführen ist ; dies ist nur ein harmloses Beispiel, tatsächlich entstehen so schwer zu durchschauende Fehler, ; die kaum zu entdecken sind. Man sollte daher die dynamische Bindung meiden. Schwachstelle der lexikalischen/statischen Bindung ; es wird ein LISP mit statischer Bindung verwendet ; es soll eine non-while-Schleife definiert werden, ; die mit einer while-Schleife konstruiert wird: (while ) (defun nonwhile (p b) (while (not (eval p)) (eval b))) ; es soll damit eine Anwendung realisiert werden (mit "begin" ist ein Block gemeint) (defun fakultaet (n) (let ((f 1)) (nonwhile '(= n 0) '(begin (setq f (* f n)) (setq n (- n 1)))) f)) ; so wird das nix, denn die statische Bindung lässt soetwas nicht zu. Man müsste schon die ; dynamische Bindung verwenden, damit es einwandfrei funktioniert, solange man nicht "p" und "b" ; in der Anwendung gebraucht (auch ein Problem). ; Um eval mit einer statischen Bindung einzusetzen, kann man (eval ) ; verwenden. (Was in diesem Beispiel aber nicht weiter hilft.) ; vielleicht kann ein LISP-Profi hier einige Auswege aufzeichnen! fpii würde folgende Lösung anbieten " nonwhile " nonwhile:=((not°(_1°self) on arg)->(self on (delobj°self) on arg);arg) fakultät:=(2°((1=0&) nonwhile (dec°1),(2*1),nil)°id,(1&),nil) Weblinks * Can Programming Be Liberated from the von Neumann Style? A Functional Style and Its Algebra of Programs Stanford University -- Artikel mit Foto von Backus (Stand 1978) * Kritik am Backus-Aufsatz von Prof. Dr. E. W. Dijkstra * beta-Version eines Interpreters für fpii Kategorie:Programmiersprache Kategorie:funktionale Programmiersprache Kategorie:objektorientierte Programmiersprache